import { useRef, useState, useMemo, type FC, useLayoutEffect } from 'react';
import { ScaleContext, INIT_SCALE } from './context';

type TProps = {
    className: string;
    containerClassName: string;
    viewportClassName: string;
    designWidth: number;
    designHeight: number;
    viewportWidth: number | string;
    viewportHeight: number | string;
    isCenter: boolean;
    mode: 'scaleX' | 'scaleY' | 'cover' | 'none';
    children: any;
};

/**
 * 视口放缩管理
 */
const ViewScaleManager: FC<Partial<TProps>> = (props) => {
    const {
        className,
        containerClassName,
        viewportClassName,
        designWidth = 1920,
        designHeight = 1080,
        viewportWidth = 1920,
        viewportHeight = 1080,
        mode = 'scaleX',
        isCenter = false,
        children,
    } = props;

    const [scale, setScale] = useState(INIT_SCALE);
    const ref = useRef({ initClient: false });

    const config = useMemo(() => {
        return { width: designWidth, height: designHeight };
    }, [designHeight, designWidth]);

    const domElementRef = useRef<HTMLDivElement>(null);
    const parentNodeRef = useRef<HTMLDivElement>(null);

    const resizeAuto = (width: number, height: number) => {
        try {
            const cw = parentNodeRef.current!.clientWidth;
            const ch = parentNodeRef.current!.clientHeight;
            const scaleX = cw / width;
            const scaleY = ch / height;
            setScale({ scaleX, scaleY });
            return {
                transform: `scale(${scaleX}, ${scaleY})`,
            };
        } catch (error) {
            return {
                transform: `scale(1, 1)`,
            };
        }
    };

    const resizeWidth = (width: number) => {
        try {
            // eslint-disable-next-line @typescript-eslint/no-shadow
            const scale = parentNodeRef.current!.clientWidth / width;
            setScale({ scaleX: scale, scaleY: scale });
            return {
                transform: `scale(${scale})`,
            };
        } catch (error) {
            return {
                transform: `scale(${1})`,
            };
        }
    };

    const resizeHeight = (width: number, height: number) => {
        try {
            // const cw = parentNodeRef.current!.clientWidth;
            const ch = parentNodeRef.current!.clientHeight;
            // eslint-disable-next-line @typescript-eslint/no-shadow
            const scale = ch / height;
            // const gap = (cw - width * scale) / 2;
            setScale({ scaleX: scale, scaleY: scale });
            return {
                // left: `${gap.toFixed(3)}px`,
                transform: `scale(${scale})`,
            };
        } catch (error) {
            return {
                // left: `${gap.toFixed(3)}px`,
                transform: `scale(${1})`,
            };
        }
    };

    const resize = (sizeConfig: any) => {
        let styles: any = {};
        switch (mode) {
            case 'cover':
                styles = resizeAuto(sizeConfig.width, sizeConfig.height);
                break;
            case 'scaleX':
                styles = resizeWidth(sizeConfig.width);
                break;
            case 'scaleY':
                styles = resizeHeight(sizeConfig.width, sizeConfig.height);
                break;
            case 'none':
                setScale({ scaleX: 1, scaleY: 1 });
                styles = { transform: 'scale(1,1)' };
                break;
            default:
                break;
        }

        if (isCenter && mode !== 'none') {
            Object.assign(domElementRef.current!.style, {
                left: '50%',
                top: '50%',
                transform: `translate(-50% , -50%) ${styles.transform ?? ''}`,
                transformOrigin: 'unset',
            });
        } else {
            Object.assign(domElementRef.current!.style, { ...styles, left: 0, top: 0, transformOrigin: 'left top' });
        }
    };

    const initPageInfo = (infoConfig: any) => {
        if (!infoConfig.width || !infoConfig.height) return;

        document.querySelector('meta[name="viewport"]')!.setAttribute('content', `width=${infoConfig.width}`);

        Object.assign(domElementRef.current!.style, {
            width: `${infoConfig.width}px`,
            height: `${infoConfig.height}px`,
        });

        resize(infoConfig);
    };

    const latest = useRef({ initPageInfo, resize });
    latest.current = {
        ...latest.current,
        initPageInfo,
        resize,
    };

    useLayoutEffect(() => {
        const domElement = parentNodeRef.current;
        // eslint-disable-next-line @typescript-eslint/no-shadow
        const { initPageInfo, resize } = latest.current;

        if (!domElement) return;

        initPageInfo(config);
        const resizeHandler = () => {
            ref.current.initClient = true;
            resize(config);
        };

        window.addEventListener('resize', resizeHandler);

        const observer = new ResizeObserver((entries) => {
            entries.forEach((entry) => {
                if (entry.target === domElement) {
                    resizeHandler();
                }
            });
        });
        observer.observe(domElement);
        return () => {
            window.removeEventListener('resize', resizeHandler);
            observer.unobserve(domElement);
        };
    }, [config, mode, isCenter]);

    return (
        <ScaleContext.Provider value={scale}>
            <section className={`rc-scale-manager-viewport  ${viewportClassName ?? ''}`} style={{ width: viewportWidth, height: viewportHeight }}>
                <div
                    className={`rc-scale-manager ${className ?? ''}`}
                    ref={parentNodeRef}
                    style={{ position: 'relative', left: 0, top: 0, width: '100%', height: '100%' }}
                >
                    <div
                        ref={domElementRef}
                        className={`rc-scale-container ${containerClassName ?? ''}`}
                        style={{
                            position: 'absolute',
                            left: 0,
                            top: 0,
                            width: '100%',
                            height: '100%',
                            overflow: 'hidden',
                            transformOrigin: 'left top',
                            display: ref.current.initClient ? 'block' : 'none',
                        }}
                    >
                        {children}
                    </div>
                </div>
            </section>
        </ScaleContext.Provider>
    );
};

export { ViewScaleManager };
